package org.tigris.atlas.jmx.weblogic;

import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import weblogic.management.MBeanHome;
import weblogic.management.WebLogicMBean;
import weblogic.management.configuration.ClusterMBean;
import weblogic.management.configuration.ConfigurationException;
import weblogic.management.configuration.ServerMBean;
import weblogic.management.configuration.TargetMBean;

/**
 * Manages the configuration of a JMS Server
 */
public class JMSServerConfiguration extends AbstractResourceConfiguation {
	
	static final String JMS_SERVER = "JMSServer";
	private Log log = LogFactory.getLog(JMSServerConfiguration.class);	
	
	/**
	 * Creates a new instance of this configuration object
	 * @param mBeanName The name of the resource to manage
	 * @param properties The properties from which to manage the resorce
	 */
	public JMSServerConfiguration(String mBeanName, Properties properties) {
		super(mBeanName, properties);
	}
	
	/**
	 * @see org.tigris.atlas.jmx.weblogic.AbstractResourceConfiguation#getLog()
	 */
	protected Log getLog() {
		return log;
	}

	/**
	 * @see org.tigris.atlas.jmx.weblogic.AbstractResourceConfiguation#getMBeanType()
	 */
	protected String getMBeanType() {
		return JMS_SERVER;
	}

	/**
	 * @see org.tigris.atlas.jmx.weblogic.AbstractResourceConfiguation#setMBeanAttributes(weblogic.management.configuration.TargetMBean[], weblogic.management.WebLogicMBean, weblogic.management.MBeanHome)
	 */
	protected void setMBeanAttributes(TargetMBean[] targetServers, WebLogicMBean mBean, MBeanHome home) {
		String dataStore = properties.getProperty(JMSJDBCStoreConfiguration.JMS_JDBC_STORE_NAME);
		WebLogicMBean dataStoreMBean = getMBean(home, dataStore, JMSJDBCStoreConfiguration.JMS_JDBC_STORE);
		try {
			dataStoreMBean.setParent(mBean);
			if (log.isInfoEnabled()) {
				log.info("Associated data store '" + dataStore + "' with " + JMS_SERVER + " '" + getMBeanName() + "'.");
			}
		} catch (ConfigurationException ce) {
			if (log.isErrorEnabled()) {
				log.error("Error adding data store '" + dataStore + "' to " + JMS_SERVER + " '" + getMBeanName() + "'!", ce);
			}
		}
				
		String queueName = properties.getProperty(JMSQueueConfiguration.JMS_QUEUE_NAME);
		JMSQueueConfiguration jmsQueueConfiguration = new JMSQueueConfiguration(queueName, properties);
		
		//TODO: change the way recreateExistingResources is propogated:
		WebLogicMBean jmsQueueMBean = jmsQueueConfiguration.configure(home, targetServers, true);
		try {			
			jmsQueueMBean.setParent(mBean);
			if (log.isInfoEnabled()) {
				log.info("Associated queue '" + queueName + "' with " + JMS_SERVER + " '" + getMBeanName() + "'.");
			}
		} catch (ConfigurationException ce) {
			if (log.isErrorEnabled()) {
				log.error("Error adding queue '" + queueName + "' to " + JMS_SERVER + " '" + getMBeanName() + "'!", ce);
			}
		}
		
		TargetMBean[] jmsServerTargets = resolveJMSServerTargets(targetServers);
		
		//set targets:
		targetToServers(jmsServerTargets, mBean);
				
	}

	/**
	 * JMSServers have different targeting requirements than otherr resources.  They can only be targeted to a 
	 * single server at a time.  This method helps determine which server to use as a target which clusters are
	 * involed.
	 * @param targetServers The base servers/clusters on which to target a resource
	 * @return The updated server this JMSServer should be target towards
	 */
	private TargetMBean[] resolveJMSServerTargets(TargetMBean[] targetServers) {
		//targeting a JMS server is different than other services.  A JMSServer can only be deployed to a single 
		//server in a cluster.  If we have a cluster, default to one of its servers:
		boolean hasBeenTargeted = false;
		int numberOfTargets = targetServers.length;
		TargetMBean[] jmsServerTargets = new TargetMBean[1];		
		for (int i = 0; i < numberOfTargets; i++) {
			if ((!hasBeenTargeted) && (WeblogicConfiguration.WLS_JMX_CLUSTER_TYPE.equals(targetServers[i].getType()))) {
				ClusterMBean cluster = (ClusterMBean)targetServers[i];
				ServerMBean[] clusterServers = cluster.getServers();
				//take the first one and make it the JMSServer:
				ServerMBean targetJMSServer = clusterServers[0];
								
				jmsServerTargets[i] = targetJMSServer;
				hasBeenTargeted = true;
				
				if (log.isInfoEnabled()) {
					log.info("Using '" + targetJMSServer.getName() + "' as the " + JMS_SERVER + " target in cluster '" + cluster.getName() + "'");
				}
				
			} else if (!hasBeenTargeted) {
				jmsServerTargets[i] = targetServers[i];
				hasBeenTargeted = true;
				
				if (log.isInfoEnabled()) {
					log.info("Using '" + jmsServerTargets[i].getName() + "' as the " + JMS_SERVER + " target");
				}
				
			} else {
				if (log.isInfoEnabled()) {
					log.info("Using '" + jmsServerTargets[0].getName() + "' as the " + JMS_SERVER + " target." +
						"  Only one " + JMS_SERVER + " can exist in a domain, do '"	+ targetServers[i].getName() + 
						"' will will be ignored");
				}
				
			}
			
		}
		return jmsServerTargets;
	}

}
